//
//  ZYHttpSessionManager.m
//  ZYWebImage
//
//  Created by wangzhipan on 2025/4/1.
//

#import "ZYHttpSessionManager.h"
#import "ZYJSONResponseSerializer.h"

@interface ZYHttpSessionManager()
@property (nonatomic, strong, nullable, readwrite) NSURL *baseUrl;

@end

@implementation ZYHttpSessionManager
+ (instancetype)manager
{
    return [[self alloc] initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(nullable NSURL *)baseUrl
{
    return [self initWithBaseURL:baseUrl sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)sessionConfiguration
{
    return [self initWithBaseURL:nil sessionConfiguration:sessionConfiguration];
}


- (instancetype)initWithBaseURL:(nullable NSURL *)url
           sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
{
    if (self = [super initWithSessionConfiguration:configuration]) {
        if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
            url = [url URLByAppendingPathComponent:@""];
        }
        self.baseUrl = url;
        self.requestSerializer = [ZYHTTPRequestSerializer serializer];
        self.responseSerializer = [ZYJSONResponseSerializer serializer];
    }
    return self;
}

- (NSURLSessionTask *)HEAD:(NSString *)urlStr
                    params:(NSDictionary *)params
                   headers:(NSDictionary<NSString *,NSString *> *)headers
                   success:(ZYSuccessBlock)success
                   failure:(ZYFailureBlock)failure
{
    NSURLSessionTask *task = [self p_dataTaskWithHTTPMethod:@"HEAD"
                                                     urlStr:urlStr
                                                     params:params
                                                    headers:headers
                                                    success:success
                                                    failure:failure];
    [task resume];
    return task;
}

- (nullable NSURLSessionTask *)GET:(NSString *)urlStr
                            params:(nullable NSDictionary *)params
                           headers:(nullable NSDictionary<NSString *, NSString *> *)headers
                           success:(ZYSuccessBlock)success
                           failure:(ZYFailureBlock)failure
{
    NSURLSessionTask *task = [self p_dataTaskWithHTTPMethod:@"GET"
                                                     urlStr:urlStr
                                                     params:params
                                                    headers:headers
                                                    success:success
                                                    failure:failure];
    [task resume];
    return task;
}

- (nullable NSURLSessionTask *)POST:(NSString *)urlStr
                             params:(nullable NSDictionary *)params
                            headers:(nullable NSDictionary<NSString *, NSString *> *)headers
                            success:(ZYSuccessBlock)success
                            failure:(ZYFailureBlock)failure
{
    NSURLSessionTask *task = [self p_dataTaskWithHTTPMethod:@"POST"
                                                     urlStr:urlStr
                                                     params:params
                                                    headers:headers
                                                    success:success
                                                    failure:failure];
    [task resume];
    return task;
}

//上传小文件
- (nullable NSURLSessionTask *)upload:(NSString *)urlStr
                                 name:(NSString *)name
                             fileName:(NSString *)fileName
                             mimeType:(NSString *)mimeType
                                 data:(NSData *)data
                               params:(nullable NSDictionary<NSString *, NSString *> *)params
                        progressBlock:(ZYProgressBlock)progressBlock
                              success:(ZYSuccessBlock)success
                              failure:(ZYFailureBlock)failure
{
    NSString *requestUrlStr = [[NSURL URLWithString:urlStr relativeToURL:self.baseUrl] absoluteString];
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer uploadWithUrlString:requestUrlStr
                                                                        params:params
                                                                          name:name
                                                                      fileName:fileName
                                                                          data:data
                                                                      mimeType:mimeType
                                                                         error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }
    __block NSURLSessionTask *task = [self uploadTaskWithRequest:request
                                                  uploadProgress:progressBlock
                                                  completedBlock:^(NSURLResponse * _Nonnull response, id  _Nullable rspObj, NSError * _Nullable error) {
        if (error) {
            failure ? failure(task, error) : nil;
        }
        else {
            success ? success(task, rspObj) : nil;
        }
    }];
    [task resume];
    return task;
}

//上传大文件
- (nullable NSURLSessionTask *)upload:(NSString *)urlStr
                                 name:(NSString *)name
                             fileName:(NSString *)fileName
                             mimeType:(NSString *)mimeType
                              fileUrl:(NSURL *)fileUrl
                               params:(nullable NSDictionary<NSString *, NSString *> *)params
                        progressBlock:(ZYProgressBlock)progressBlock
                              success:(ZYSuccessBlock)success
                              failure:(ZYFailureBlock)failure
{
    NSString *requestUrlStr = [[NSURL URLWithString:urlStr relativeToURL:self.baseUrl] absoluteString];
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer uploadWithUrlString:requestUrlStr
                                                                        params:params
                                                                          name:name
                                                                      fileName:fileName
                                                                       fileUrl:fileUrl
                                                                      mimeType:mimeType
                                                                         error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }
    __block NSURLSessionTask *task = [self uploadTaskWithStreamedRequest:request
                                                          uploadProgress:progressBlock
                                                          completedBlock:^(NSURLResponse * _Nonnull response, id  _Nullable rspObj, NSError * _Nullable error) {
        if (error) {
            failure ? failure(task, error) : nil;
        }
        else {
            success ? success(task, rspObj) : nil;
        }
    }];
    [task resume];
    return task;
}


- (nullable NSURLSessionTask *)p_dataTaskWithHTTPMethod:(NSString *)method
                                                 urlStr:(NSString *)urlStr
                                                 params:(nullable NSDictionary *)params
                                                headers:(nullable NSDictionary<NSString *, NSString *> *)headers
                                                success:(ZYSuccessBlock)success
                                                failure:(ZYFailureBlock)failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method 
                                                                   URLString:[[NSURL URLWithString:urlStr relativeToURL:self.baseUrl] absoluteString]
                                                                  parameters:params
                                                                       error:&serializationError];
    for (NSString *headerField in headers.keyEnumerator) {
        [request setValue:headers[headerField] forHTTPHeaderField:headerField];
    }
    if (serializationError) {
        if (failure) {
            dispatch_async(dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }
    __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request
                                                        completedBlock:^(NSURLResponse * _Nonnull response, id  _Nullable rspObj, NSError * _Nullable error) {
        if (error) {
            failure ? failure(task, error) : nil;
        }
        else {
            success ? success(task, rspObj) : nil;
        }
    }];
    return task;
}


@dynamic securityPolicy;
- (void)setSecurityPolicy:(ZYSecurityPolicy *)securityPolicy {
    if (securityPolicy.SSLPinningMode != ZYSSLPinningModeNone && ![self.baseUrl.scheme isEqualToString:@"https"]) {
        NSString *pinningMode = @"Unknown Pinning Mode";
        switch (securityPolicy.SSLPinningMode) {
            case ZYSSLPinningModeNone:        pinningMode = @"AFSSLPinningModeNone"; break;
            case ZYSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
            case ZYSSLPinningModePublicKey:   pinningMode = @"AFSSLPinningModePublicKey"; break;
        }
        NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
        @throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
    }

    [super setSecurityPolicy:securityPolicy];
}
@end
